/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2018-2018. All rights reserved.
 * Description: Huawei safe print function define
 *
 * Huawei(R) HiNIC PCI Express Network Controller UEFI Driver.
 * This driver is only usable in the EFI Pre-boot execution environment.
 * All rights reserved.
 * Author	 :
 * Create	 : 2018/12/10
 */
#include "HwSafeOpInternal.h"
#include "HwSafeMemOpWrapper.h"

EFI_STATUS MemCheckParameter(
    void *dest,
    UINTN destMax,
    const void *src,
    UINTN count)
{
    BOOLEAN bDestMaxInvalid = FALSE;
    BOOLEAN bAddrInvalid = FALSE;

    // destMax size invalid
    bDestMaxInvalid = (destMax == 0 || destMax > EFI_SECUREC_MEM_MAX_LEN);
    if (bDestMaxInvalid) {
        return EFI_BAD_BUFFER_SIZE;
    }

    // dest or src addr invalid
    bAddrInvalid = (dest == NULL || src == NULL);
    if (bAddrInvalid) {
        if (dest != NULL) {
            (void)SetMem(dest, destMax, 0);
        }
        return EFI_INVALID_PARAMETER;
    }

    // dest buffer overflow
    if (count > destMax) {
        (void)SetMem(dest, destMax, 0);
        return EFI_BUFFER_TOO_SMALL;
    }

    return EFI_SUCCESS;
}

/*******************************************************************************
* <FUNCTION DESCRIPTION>
*    Copies the value of c (converted to an unsigned char) into
*    each of the first count characters of the object pointed to by dest.
*
* <INPUT PARAMETERS>
*    dest                       Pointer to destination.
*    destMax                    The size of the buffer.
*    c                          Character to set.
*    count                      Number of characters.
*
* <OUTPUT PARAMETERS>
*    dest buffer                is uptdated.
*
* <RETURN VALUE>
*    EFI_SUCCESS                        Success
*    EFI_INVALID_PARAMETER       dest is NULL
*    EFI_BUFFER_TOO_SMALL        count larger than destMax
*
********************************************************************************/
EFI_STATUS MemSetS(
    void *dest,
    UINTN destMax,
    UINT8 c,
    UINTN count)
{
    BOOLEAN bDestMaxInvalid = FALSE;

    bDestMaxInvalid = (destMax == 0 || destMax > EFI_SECUREC_MEM_MAX_LEN);
    // destMax is invalid
    if (bDestMaxInvalid) {
        return EFI_BAD_BUFFER_SIZE;
    }

    // dest addr is NULL
    if (dest == NULL) {
        return EFI_INVALID_PARAMETER;
    }

    // count is overflow
    if (count > destMax) {
        (void)SetMem(dest, destMax, c);   // set entire buffer to value c
        return EFI_BUFFER_TOO_SMALL;
    }

    if (count > 0) {
        // use underlying memcpy for performance consideration
        (void)SetMem(dest, count, c);
    }

    return EFI_SUCCESS;
}

/*******************************************************************************
* <FUNCTION DESCRIPTION>
*    Copies count bytes of characters from the object pointed to by src into the object pointed to by dest.
*
* <INPUT PARAMETERS>
*    dest                       Pointer to destination buffer.
*    destMax                  The max size of the destination buffer.
*    src                          Pointer to source buffer.
*    count                      Bytes of data to copy.
*
* <OUTPUT PARAMETERS>
*    dest buffer                is uptdated.
*
* <RETURN VALUE>
*    EFI_SUCCESS                        Success
*    EFI_INVALID_PARAMETER       dest is NULL or src is NULL
*    EFI_BAD_BUFFER_SIZE           destMax invalid
*    EFI_BUFFER_TOO_SMALL        dest buffer overflow
*    EFI_ACCESS_DENIED             Check if src and dest overlap
*
********************************************************************************/
EFI_STATUS MemCpyS(
    void *dest,
    UINTN destMax,
    const void *src,
    UINTN count)
{
    EFI_STATUS eStatus;
    BOOLEAN bOverlap = FALSE;

    eStatus = MemCheckParameter(dest, destMax, src, count);
    if (EFI_ERROR(eStatus)) {
        return eStatus;
    }

    if (dest == src) {
        return EFI_SUCCESS;
    }

    // check if src and dest overlap
    bOverlap = ((src < dest && (void*)((UINT8*)src + count) > dest) ||
                    (dest < src && (void*)((UINT8*)dest + count) > src));
    if (bOverlap) {
        (void)SetMem(dest, destMax, 0);
        return EFI_ACCESS_DENIED;
    }

    if (count > 0) {
        // use underlying memcpy for performance consideration
        (void)CopyMem(dest, src, count);
    }

    return EFI_SUCCESS;
}

/*******************************************************************************
* <FUNCTION DESCRIPTION>
*    Copies count bytes of characters from src to dest.
*
* <INPUT PARAMETERS>
*    dest                       Pointer to destination buffer.
*    destMax                  The max size of the destination buffer.
*    src                          Pointer to source buffer.
*    count                      Bytes of data to move.
*
* <OUTPUT PARAMETERS>
*    dest buffer                is uptdated.
*
* <RETURN VALUE>
*    EFI_SUCCESS                        Success
*    EFI_INVALID_PARAMETER       dest is NULL or src is NULL
*    EFI_BAD_BUFFER_SIZE          destMax invalid
*    EFI_BUFFER_TOO_SMALL       dest buffer overflow
*
********************************************************************************/
EFI_STATUS MemMoveS(
    void *dest,
    UINTN destMax,
    const void *src,
    UINTN count)
{
    EFI_STATUS eStatus;

    eStatus = MemCheckParameter(dest, destMax, src, count);
    if (EFI_ERROR(eStatus)) {
        return eStatus;
    }

    if (dest == src) {
        return EFI_SUCCESS;
    }

    if (count > 0) {
        // use underlying memmove for performance consideration
        (void)CopyMem(dest, src, count);
    }

    return EFI_SUCCESS;
}

